#!/bin/bash

# QT+OpenCV交叉编译打包脚本 - aarch64版本
# 版本号: 2.0.9
# 更新日期: 2025-11-12
# 使用方法: ./package_app.sh [可执行文件路径] [输出目录] [资源目录(可选)]

# 脚本版本信息
SCRIPT_VERSION="2.0.9"
SCRIPT_DATE="2025-11-12"
SCRIPT_AUTHOR=""

# 配置参数 - 根据您提供的路径
QT_ARM_DIR="/opt/qt/qt5.15.3-arm-old"              # ARM QT库目录
OPENCV_ARM_DIR="/usr/local/opencv-arm64"           # ARM OpenCV库目录  
CROSS_COMPILE_TOOLCHAIN="/opt/Qt/gcc/linux-x86/aarch64/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu"  # 交叉编译工具链
TARGET_ARCH="aarch64-linux-gnu"                   # 目标架构
DEFAULT_RESOURCES_DIR="/opt/qt/Programs/resource/3D"               # 默认资源目录

# 显示使用帮助
show_usage() {
    echo "QT+OpenCV交叉编译打包工具 v${SCRIPT_VERSION}"
    echo "更新日期: ${SCRIPT_DATE}"
    echo ""
    echo "用法: $0 [选项] <可执行文件> <输出目录> [资源目录]"
    echo "选项:"
    echo "  -h, --help                 显示此帮助信息"
    echo "  -v, --version              显示版本信息"
    echo "  -q, --qt-dir <目录>        指定QT ARM库目录 (默认: $QT_ARM_DIR)"
    echo "  -o, --opencv-dir <目录>    指定OpenCV ARM库目录 (默认: $OPENCV_ARM_DIR)"
    echo "  -t, --toolchain <目录>     指定交叉编译工具链目录 (默认: $CROSS_COMPILE_TOOLCHAIN)"
    echo "  -a, --arch <架构>          指定目标架构 (默认: $TARGET_ARCH)"
    echo "  -r, --resources <目录>     指定资源文件目录 (默认: $DEFAULT_RESOURCES_DIR)"
    echo ""
    echo "示例:"
    echo "  $0 ./myapp ./output                        # 使用默认资源目录"
    echo "  $0 ./myapp ./output ./my_resources         # 使用指定资源目录"
    echo "  $0 -r ./custom_resources ./myapp ./output  # 使用选项指定资源目录"
    echo "  $0 -q /opt/my-qt-arm -o /opt/my-opencv-arm -r ./resources ./myapp ./output"
}

# 显示版本信息
show_version() {
    echo "QT+OpenCV交叉编译打包工具"
    echo "版本: v${SCRIPT_VERSION}"
    echo "更新日期: ${SCRIPT_DATE}"
    echo "作者: ${SCRIPT_AUTHOR}"
    echo "目标架构: ${TARGET_ARCH}"
    echo "QT目录: ${QT_ARM_DIR}"
    echo "OpenCV目录: ${OPENCV_ARM_DIR}"
    echo "工具链: ${CROSS_COMPILE_TOOLCHAIN}"
    echo "默认资源目录: ${DEFAULT_RESOURCES_DIR}"
}

# 解析命令行参数
RESOURCES_DIR=""
while [[ $# -gt 0 ]]; do
    case $1 in
        -h|--help)
            show_usage
            exit 0
            ;;
        -v|--version)
            show_version
            exit 0
            ;;
        -q|--qt-dir)
            QT_ARM_DIR="$2"
            shift 2
            ;;
        -o|--opencv-dir)
            OPENCV_ARM_DIR="$2"
            shift 2
            ;;
        -t|--toolchain)
            CROSS_COMPILE_TOOLCHAIN="$2"
            shift 2
            ;;
        -a|--arch)
            TARGET_ARCH="$2"
            shift 2
            ;;
        -r|--resources)
            RESOURCES_DIR="$2"
            shift 2
            ;;
        -*)
            echo "错误: 未知选项 $1"
            show_usage
            exit 1
            ;;
        *)
            break
            ;;
    esac
done

# 检查必需参数
if [[ $# -lt 2 ]]; then
    echo "错误: 缺少必需参数"
    show_usage
    exit 1
fi

EXECUTABLE="$1"
OUTPUT_DIR="$2"

# 第三个参数作为资源目录（如果未使用-r选项）
if [[ $# -ge 3 && -z "$RESOURCES_DIR" ]]; then
    RESOURCES_DIR="$3"
fi

# 如果仍未指定资源目录，使用默认值
if [[ -z "$RESOURCES_DIR" ]]; then
    RESOURCES_DIR="$DEFAULT_RESOURCES_DIR"
    echo "使用默认资源目录: $RESOURCES_DIR"
fi

APP_NAME=$(basename "$EXECUTABLE")
PACKAGE_NAME="${APP_NAME}_aarch64_package"

# 检查可执行文件是否存在
if [[ ! -f "$EXECUTABLE" ]]; then
    echo "错误: 可执行文件 '$EXECUTABLE' 不存在"
    exit 1
fi

# 初始化变量
PACKAGE_DIR=""

# 检查可执行文件架构
check_binary_arch() {
    local binary="$1"
    echo "检查可执行文件架构..."
    
    if file "$binary" | grep -q "ELF 64-bit.*aarch64"; then
        echo "✓ 可执行文件是aarch64架构"
        return 0
    else
        echo "✗ 错误: 可执行文件不是aarch64架构"
        file "$binary"
        return 1
    fi
}

# 检查交叉编译工具链
check_toolchain() {
    echo "检查交叉编译工具链..."
    
    local ldd_path="${CROSS_COMPILE_TOOLCHAIN}/bin/${TARGET_ARCH}-ldd"
    local readelf_path="${CROSS_COMPILE_TOOLCHAIN}/bin/${TARGET_ARCH}-readelf"
    
    if [[ -f "$ldd_path" ]]; then
        echo "✓ 找到ldd工具: $ldd_path"
        LDD_TOOL="$ldd_path"
    elif [[ -f "$readelf_path" ]]; then
        echo "✓ 找到readelf工具: $readelf_path"
        READELF_TOOL="$readelf_path"
    else
        echo "✗ 警告: 未找到交叉编译工具链的ldd或readelf"
        echo "将使用本地ldd（可能不准确）"
        LDD_TOOL="ldd"
    fi
}

# 创建输出目录结构
create_directories() {
    local base_dir="$OUTPUT_DIR/$PACKAGE_NAME"
    echo "创建目录结构: $base_dir"
    
    # 确保输出目录存在
    mkdir -p "$OUTPUT_DIR" || {
        echo "错误: 无法创建输出目录 $OUTPUT_DIR"
        exit 1
    }
    
    # 创建包目录结构
    mkdir -p "$base_dir/libs" || {
        echo "错误: 无法创建libs目录"
        exit 1
    }
    mkdir -p "$base_dir/plugins/platforms" || {
        echo "错误: 无法创建platforms目录"
        exit 1
    }
    mkdir -p "$base_dir/plugins/imageformats" || {
        echo "错误: 无法创建imageformats目录"
        exit 1
    }
    mkdir -p "$base_dir/plugins/bearer" || {
        echo "错误: 无法创建bearer目录"
        exit 1
    }
    mkdir -p "$base_dir/plugins/printsupport" || {
        echo "错误: 无法创建printsupport目录"
        exit 1
    }
    mkdir -p "$base_dir/bin" || {
        echo "错误: 无法创建bin目录"
        exit 1
    }
    
    echo "$base_dir"
}

# 复制资源文件
copy_resources() {
    local resources_dir="$1"
    local target_dir="$2"
    
    if [[ -z "$resources_dir" || ! -d "$resources_dir" ]]; then
        echo "资源目录 '$resources_dir' 不存在，跳过资源文件复制"
        return 0
    fi
    
    echo "复制资源文件从: $resources_dir"
    
    # 检查资源目录内容
    echo "资源目录内容:"
    find "$resources_dir" -type f -o -type d | while read item; do
        if [[ "$item" != "$resources_dir" ]]; then
            local relative_path="${item#$resources_dir/}"
            echo "  - $relative_path"
        fi
    done
    
    # 复制所有文件和目录结构
    echo "正在复制资源文件..."
    if cp -r "$resources_dir"/* "$target_dir/bin/" 2>/dev/null; then
        local resource_count=$(find "$resources_dir" -type f | wc -l)
        echo "✓ 复制了 $resource_count 个资源文件到 bin 目录"
        
        # 显示复制的文件列表
        echo "已复制的资源文件:"
        find "$resources_dir" -type f | while read file; do
            local filename=$(basename "$file")
            echo "  - $filename"
        done
    else
        echo "✗ 复制资源文件时出错"
        return 1
    fi
    
    return 0
}

# 创建符号链接
create_symlinks() {
    local target_dir="$1"
    
    echo "创建库文件符号链接..."
    
    if [[ ! -d "$target_dir/libs" ]]; then
        echo "错误: libs目录不存在"
        return 1
    fi
    
    cd "$target_dir/libs" || return 1
    
    # 查找所有.so文件并创建符号链接
    find . -name "*.so.*" -type f | while read -r lib_file; do
        local lib_basename=$(basename "$lib_file")
        
        # 提取基础名称（去掉版本号）
        local base_name=$(echo "$lib_basename" | sed 's/\.so\..*/.so/')
        local major_name=$(echo "$lib_basename" | sed 's/\.so\..*/.so/' | sed 's/\.so$/.so.5/')  # 对于Qt5库
        
        # 创建无版本号符号链接
        if [[ ! -L "$base_name" && "$lib_basename" != "$base_name" ]]; then
            echo "创建符号链接: $base_name -> $lib_basename"
            ln -sf "$lib_basename" "$base_name" 2>/dev/null || true
        fi
        
        # 创建主版本号符号链接（针对Qt5库）
        if [[ "$lib_basename" =~ \.so\.5\..* ]] && [[ ! -L "$major_name" ]]; then
            echo "创建符号链接: $major_name -> $lib_basename"
            ln -sf "$lib_basename" "$major_name" 2>/dev/null || true
        fi
    done
    
    cd - >/dev/null
    echo "符号链接创建完成"
}

# 获取动态库依赖
get_dependencies() {
    local binary="$1"
    echo "正在分析 $binary 的依赖库..."
    
    if [[ -n "$LDD_TOOL" && "$LDD_TOOL" != "ldd" ]]; then
        # 使用交叉编译工具链的ldd
        "$LDD_TOOL" "$binary" 2>/dev/null | grep -E "=>|not" | while read -r line; do
            if echo "$line" | grep -q "=>"; then
                # 格式: libxxx.so => /path/to/libxxx.so
                echo "$line" | awk '{print $3}'
            elif echo "$line" | grep -q "not found"; then
                # 格式: libxxx.so not found
                lib_name=$(echo "$line" | awk '{print $1}')
                echo "未找到: $lib_name" >&2
            fi
        done
    elif [[ -n "$READELF_TOOL" ]]; then
        # 使用readelf分析依赖
        "$READELF_TOOL" -d "$binary" 2>/dev/null | grep "Shared library" | awk -F'[][]' '{print $2}' | sort -u
    else
        # 使用本地ldd作为备选
        echo "警告: 使用本地ldd分析ARM二进制文件，结果可能不准确"
        ldd "$binary" 2>/dev/null | grep "=>" | awk '{print $3}' | grep -v "^$" || true
    fi
}

# 查找库文件
find_library() {
    local lib_name="$1"
    local found_path=""
    
    # 如果已经是完整路径且文件存在
    if [[ $lib_name == /* ]] && [[ -f "$lib_name" ]]; then
        echo "$lib_name"
        return 0
    fi
    
    # 提取基础库名（去掉版本号）
    local base_lib_name=$(echo "$lib_name" | sed 's/\.so\..*//' | sed 's/\.so$//')
    base_lib_name="${base_lib_name}.so"
    
    # 搜索目录列表
    local search_dirs=(
        "$QT_ARM_DIR/lib"
        "$OPENCV_ARM_DIR/lib"
        "$CROSS_COMPILE_TOOLCHAIN/lib"
        "$CROSS_COMPILE_TOOLCHAIN/$TARGET_ARCH/lib"
        "$CROSS_COMPILE_TOOLCHAIN/$TARGET_ARCH/libc/lib"
        "/lib/$TARGET_ARCH"
        "/usr/lib/$TARGET_ARCH"
        "/usr/local/lib/$TARGET_ARCH"
    )
    
    # 首先尝试精确匹配
    for dir in "${search_dirs[@]}"; do
        if [[ -f "$dir/$lib_name" ]]; then
            found_path="$dir/$lib_name"
            break
        fi
        # 也检查符号链接
        if [[ -L "$dir/$lib_name" ]]; then
            found_path=$(readlink -f "$dir/$lib_name")
            if [[ -f "$found_path" ]]; then
                echo "$found_path"
                return 0
            fi
        fi
    done
    
    # 如果精确匹配失败，尝试模糊匹配（带版本号）
    if [[ -z "$found_path" ]]; then
        for dir in "${search_dirs[@]}"; do
            if [[ -d "$dir" ]]; then
                # 查找实际文件
                local matched_lib=$(find "$dir" -name "${base_lib_name}*" -type f 2>/dev/null | head -1)
                if [[ -n "$matched_lib" ]]; then
                    found_path="$matched_lib"
                    break
                fi
                # 查找符号链接
                local matched_symlink=$(find "$dir" -name "${base_lib_name}*" -type l 2>/dev/null | head -1)
                if [[ -n "$matched_symlink" ]]; then
                    found_path=$(readlink -f "$matched_symlink")
                    if [[ -f "$found_path" ]]; then
                        echo "$found_path"
                        return 0
                    fi
                fi
            fi
        done
    fi
    
    if [[ -n "$found_path" ]]; then
        echo "$found_path"
    else
        echo "未找到库: $lib_name" >&2
        return 1
    fi
}

# 复制库文件
copy_libraries() {
    local binary="$1"
    local target_dir="$2"
    local processed_libs=()
    
    echo "开始收集依赖库..."
    
    # 验证目标目录
    if [[ ! -d "$target_dir/libs" ]]; then
        echo "错误: 目标libs目录不存在: $target_dir/libs"
        return 1
    fi
    
    # 获取直接依赖
    local dependencies=$(get_dependencies "$binary")
    local lib_queue=()
    
    # 初始化队列
    while IFS= read -r lib_path; do
        if [[ -n "$lib_path" && -f "$lib_path" ]]; then
            lib_queue+=("$lib_path")
        fi
    done <<< "$dependencies"
    
    # 处理队列
    while [[ ${#lib_queue[@]} -gt 0 ]]; do
        local current_lib="${lib_queue[0]}"
        lib_queue=("${lib_queue[@]:1}")
        
        local lib_filename=$(basename "$current_lib")
        
        # 跳过已处理的库
        if [[ " ${processed_libs[@]} " =~ " $lib_filename " ]]; then
            continue
        fi
        
        echo "复制: $lib_filename"
        cp "$current_lib" "$target_dir/libs/" || {
            echo "错误: 无法复制库文件 $lib_filename"
            return 1
        }
        processed_libs+=("$lib_filename")
        
        # 获取这个库的依赖
        local sub_deps=$(get_dependencies "$current_lib")
        while IFS= read -r sub_lib; do
            if [[ -n "$sub_lib" && -f "$sub_lib" ]]; then
                local sub_lib_filename=$(basename "$sub_lib")
                if [[ ! " ${processed_libs[@]} " =~ " $sub_lib_filename " ]]; then
                    lib_queue+=("$sub_lib")
                fi
            fi
        done <<< "$sub_deps"
    done
    
    echo "共收集 ${#processed_libs[@]} 个库文件"
    return 0
}

# 复制QT核心库
copy_qt_core_libs() {
    local target_dir="$1"
    
    echo "复制QT核心库..."
    
    # 验证目标目录
    if [[ ! -d "$target_dir/libs" ]]; then
        echo "错误: 目标libs目录不存在"
        return 1
    fi
    
    # 常见的QT库列表
    local qt_core_libs=(
        "libQt5Core.so*"
        "libQt5Gui.so*"
        "libQt5Widgets.so*"
        "libQt5SerialPort.so*"
        "libQt5Network.so*"
        "libQt5PrintSupport.so*"
        "libQt5DBus.so*"
        "libQt5XcbQpa.so*"
        "libQt5EglFsKmsSupport.so*"
        "libQt5EglFSDeviceIntegration.so*"
        "libicudata.so*"
        "libicui18n.so*"
        "libicuuc.so*"
    )
    
    for lib_pattern in "${qt_core_libs[@]}"; do
        find "$QT_ARM_DIR/lib" -name "$lib_pattern" \( -type f -o -type l \) 2>/dev/null | while read -r lib; do
            local lib_name=$(basename "$lib")
            if [[ ! -f "$target_dir/libs/$lib_name" && ! -L "$target_dir/libs/$lib_name" ]]; then
                echo "复制QT库: $lib_name"
                cp -P "$lib" "$target_dir/libs/" || {
                    echo "错误: 无法复制QT库 $lib_name"
                }
            fi
        done
    done
    return 0
}

# 复制QT插件
copy_qt_plugins() {
    local target_dir="$1"
    
    echo "复制QT插件..."
    
    # 验证目标目录
    if [[ ! -d "$target_dir/plugins" ]]; then
        echo "错误: 目标plugins目录不存在"
        return 1
    fi
    
    # 平台插件
    if [[ -d "$QT_ARM_DIR/plugins/platforms" ]]; then
        echo "复制平台插件..."
        cp -P "$QT_ARM_DIR/plugins/platforms/"*.so "$target_dir/plugins/platforms/" 2>/dev/null || true
        
        local platform_count=0
        if [[ -d "$target_dir/plugins/platforms" ]]; then
            platform_count=$(ls "$target_dir/plugins/platforms/"*.so 2>/dev/null | wc -l)
        fi
        echo "复制平台插件: $platform_count 个"
        
        # 列出所有平台插件
        if [[ $platform_count -gt 0 ]]; then
            echo "平台插件列表:"
            ls "$target_dir/plugins/platforms/"*.so 2>/dev/null | xargs -I {} basename {} | while read plugin; do
                echo "  - $plugin"
            done
        fi
    fi
    
    # 图像格式插件
    if [[ -d "$QT_ARM_DIR/plugins/imageformats" ]]; then
        cp -P "$QT_ARM_DIR/plugins/imageformats/"*.so "$target_dir/plugins/imageformats/" 2>/dev/null || true
        local imageformat_count=0
        if [[ -d "$target_dir/plugins/imageformats" ]]; then
            imageformat_count=$(ls "$target_dir/plugins/imageformats/"*.so 2>/dev/null | wc -l)
        fi
        echo "复制图像格式插件: $imageformat_count 个"
    fi
    
    # 其他插件
    if [[ -d "$QT_ARM_DIR/plugins/bearer" ]]; then
        cp -P "$QT_ARM_DIR/plugins/bearer/"*.so "$target_dir/plugins/bearer/" 2>/dev/null || true
    fi
    
    if [[ -d "$QT_ARM_DIR/plugins/printsupport" ]]; then
        cp -P "$QT_ARM_DIR/plugins/printsupport/"*.so "$target_dir/plugins/printsupport/" 2>/dev/null || true
    fi
    
    return 0
}

# 复制OpenCV库
copy_opencv_libs() {
    local target_dir="$1"
    
    echo "复制OpenCV库..."
    
    # 验证目标目录
    if [[ ! -d "$target_dir/libs" ]]; then
        echo "错误: 目标libs目录不存在"
        return 1
    fi
    
    local opencv_libs=(
        "libopencv_core.so*"
        "libopencv_imgproc.so*"
        "libopencv_imgcodecs.so*"
        "libopencv_videoio.so*"
        "libopencv_highgui.so*"
        "libopencv_calib3d.so*"
        "libopencv_features2d.so*"
        "libopencv_video.so*"
        "libopencv_ml.so*"
        "libopencv_objdetect.so*"
    )
    
    for lib_pattern in "${opencv_libs[@]}"; do
        find "$OPENCV_ARM_DIR/lib" -name "$lib_pattern" \( -type f -o -type l \) 2>/dev/null | while read -r lib; do
            local lib_name=$(basename "$lib")
            if [[ ! -f "$target_dir/libs/$lib_name" && ! -L "$target_dir/libs/$lib_name" ]]; then
                echo "复制OpenCV库: $lib_name"
                cp -P "$lib" "$target_dir/libs/" || {
                    echo "错误: 无法复制OpenCV库 $lib_name"
                }
            fi
        done
    done
    return 0
}

# 生成运行脚本
create_run_script() {
    local target_dir="$1"
    local script_path="$target_dir/run_${APP_NAME}.sh"
    
    cat > "$script_path" << 'EOF'
#!/bin/bash

# 应用程序启动脚本
# 打包工具版本: vSCRIPT_VERSION_PLACEHOLDER
# 打包时间: PACKAGE_TIME_PLACEHOLDER

APP_DIR=$(cd $(dirname $0); pwd)
export LD_LIBRARY_PATH=$APP_DIR/libs:$APP_DIR/plugins/platforms:$APP_DIR/plugins/imageformats:$LD_LIBRARY_PATH
export QT_PLUGIN_PATH=$APP_DIR/plugins
export QT_QPA_PLATFORM_PLUGIN_PATH=$APP_DIR/plugins/platforms

# 设置默认QT平台为linuxfb（适用于嵌入式设备）
export QT_QPA_PLATFORM=linuxfb

echo "=========================================="
echo "启动应用程序: APP_NAME_PLACEHOLDER"
echo "打包版本: vSCRIPT_VERSION_PLACEHOLDER"
echo "应用程序目录: $APP_DIR"
echo "QT平台: $QT_QPA_PLATFORM"
echo "=========================================="

cd "$APP_DIR/bin"

# 检查可执行文件
if [[ ! -f "./APP_NAME_PLACEHOLDER" ]]; then
    echo "错误: 找不到可执行文件 APP_NAME_PLACEHOLDER"
    exit 1
fi

# 检查资源文件
echo "资源文件检查:"
if [[ -d "$APP_DIR/bin" ]]; then
    echo "bin目录内容:"
    ls -la "$APP_DIR/bin/" | grep -v "^total" | while read line; do
        echo "  $line"
    done
fi

# 检查平台插件
echo "可用的平台插件:"
if [[ -d "$APP_DIR/plugins/platforms" ]]; then
    ls "$APP_DIR/plugins/platforms/"*.so 2>/dev/null | xargs -I {} basename {} | while read plugin; do
        echo "  - $plugin"
    done
else
    echo "  (无平台插件)"
fi

# 检查依赖库
echo "检查依赖库..."
missing_libs=$(ldd "./APP_NAME_PLACEHOLDER" 2>/dev/null | grep "not found" | awk '{print $1}' | tr '\n' ' ')
if [[ -n "$missing_libs" ]]; then
    echo "警告: 以下库文件未找到: $missing_libs"
else
    echo "✓ 所有依赖库已找到"
fi

# 平台选择提示
echo ""
echo "平台使用说明:"
echo "=========================================="
echo "当前平台: $QT_QPA_PLATFORM"
echo "可用平台选项:"
echo "1. linuxfb    - Linux帧缓冲 (嵌入式设备推荐)"
echo "2. minimal    - 最小化平台 (无图形输出)"
echo "3. offscreen  - 离屏渲染 (无显示输出)"
echo "4. vnc        - VNC远程桌面"
echo ""
echo "如需更改平台，可设置环境变量:"
echo "  QT_QPA_PLATFORM=minimal ./run_APP_NAME_PLACEHOLDER.sh"
echo "=========================================="

echo "正在启动程序..."
./APP_NAME_PLACEHOLDER "$@"

exit $?
EOF
    
    # 替换占位符
    sed -i "s/SCRIPT_VERSION_PLACEHOLDER/${SCRIPT_VERSION}/g" "$script_path"
    sed -i "s/PACKAGE_TIME_PLACEHOLDER/$(date)/g" "$script_path"
    sed -i "s/APP_NAME_PLACEHOLDER/${APP_NAME}/g" "$script_path"
    
    chmod +x "$script_path"
    echo "已创建运行脚本: $(basename "$script_path")"
}

# 生成杀死进程脚本
create_kill_script() {
    local target_dir="$1"
    local script_path="$target_dir/kill_${APP_NAME}.sh"
    
    cat > "$script_path" << 'EOF'
#!/bin/bash

# 应用程序进程终止脚本
# 打包工具版本: vSCRIPT_VERSION_PLACEHOLDER
# 打包时间: PACKAGE_TIME_PLACEHOLDER

APP_NAME="APP_NAME_PLACEHOLDER"
APP_DIR=$(cd $(dirname $0); pwd)

echo "=========================================="
echo "终止应用程序: $APP_NAME"
echo "打包版本: vSCRIPT_VERSION_PLACEHOLDER"
echo "应用程序目录: $APP_DIR"
echo "=========================================="

# 查找进程
find_processes() {
    # 方法1: 通过进程名查找
    local pids1=$(ps aux | grep -v grep | grep "$APP_DIR/bin/$APP_NAME" | awk '{print $2}')
    
    # 方法2: 通过可执行文件路径查找
    local pids2=$(ps aux | grep -v grep | grep "$APP_NAME" | grep -v "kill_$APP_NAME" | awk '{print $2}')
    
    # 合并并去重
    echo "$pids1 $pids2" | tr ' ' '\n' | sort -u | grep -v '^$'
}

# 优雅终止函数
graceful_kill() {
    local pids=$1
    
    if [[ -z "$pids" ]]; then
        echo "✓ 应用程序 $APP_NAME 当前没有在运行"
        return 0
    fi
    
    echo "找到以下进程: $pids"
    
    # 首先尝试优雅终止 (SIGTERM)
    echo "发送优雅终止信号 (SIGTERM)..."
    for pid in $pids; do
        if kill -0 $pid 2>/dev/null; then
            echo "终止进程 $pid..."
            kill -TERM $pid
        fi
    done
    
    # 等待5秒让进程退出
    local wait_time=5
    echo "等待 ${wait_time} 秒让进程退出..."
    sleep $wait_time
    
    # 检查是否还有进程存活
    local remaining_pids=$(find_processes)
    if [[ -n "$remaining_pids" ]]; then
        echo "以下进程仍在运行: $remaining_pids"
        echo "发送强制终止信号 (SIGKILL)..."
        for pid in $remaining_pids; do
            if kill -0 $pid 2>/dev/null; then
                echo "强制终止进程 $pid..."
                kill -KILL $pid
            fi
        done
        
        # 最后检查
        sleep 1
        local final_pids=$(find_processes)
        if [[ -n "$final_pids" ]]; then
            echo "⚠ 警告: 以下进程可能无法终止: $final_pids"
            return 1
        else
            echo "✓ 所有进程已强制终止"
            return 0
        fi
    else
        echo "✓ 所有进程已优雅终止"
        return 0
    fi
}

# 强制终止函数
force_kill() {
    local pids=$1
    
    if [[ -z "$pids" ]]; then
        echo "✓ 应用程序 $APP_NAME 当前没有在运行"
        return 0
    fi
    
    echo "找到以下进程: $pids"
    echo "发送强制终止信号 (SIGKILL)..."
    
    for pid in $pids; do
        if kill -0 $pid 2>/dev/null; then
            echo "强制终止进程 $pid..."
            kill -KILL $pid
        fi
    done
    
    sleep 1
    local remaining_pids=$(find_processes)
    if [[ -n "$remaining_pids" ]]; then
        echo "⚠ 警告: 以下进程可能无法终止: $remaining_pids"
        return 1
    else
        echo "✓ 所有进程已强制终止"
        return 0
    fi
}

# 显示进程信息
show_process_info() {
    local pids=$(find_processes)
    
    if [[ -z "$pids" ]]; then
        echo "当前没有找到 $APP_NAME 的进程"
        return
    fi
    
    echo "当前运行的 $APP_NAME 进程:"
    echo "PID     USER    CPU%   MEM%   STARTED    COMMAND"
    ps -p $pids -o pid,user,pcpu,pmem,start,cmd --no-headers 2>/dev/null | while read line; do
        echo "  $line"
    done
}

# 主逻辑
case "${1:-}" in
    -f|--force)
        echo "使用强制模式终止进程..."
        pids=$(find_processes)
        force_kill "$pids"
        ;;
    -i|--info)
        echo "显示进程信息..."
        show_process_info
        exit 0
        ;;
    -h|--help)
        echo "用法: $0 [选项]"
        echo "选项:"
        echo "  -f, --force     强制终止进程 (SIGKILL)"
        echo "  -i, --info      显示进程信息，不终止"
        echo "  -h, --help      显示此帮助信息"
        echo "  无参数          优雅终止进程 (SIGTERM)"
        echo ""
        echo "示例:"
        echo "  $0              # 优雅终止"
        echo "  $0 --force      # 强制终止"
        echo "  $0 --info       # 只显示信息"
        exit 0
        ;;
    *)
        if [[ -n "$1" ]]; then
            echo "错误: 未知选项 '$1'"
            echo "使用 '$0 --help' 查看用法"
            exit 1
        fi
        
        echo "使用优雅模式终止进程..."
        pids=$(find_processes)
        graceful_kill "$pids"
        ;;
esac

# 最终状态检查
echo ""
echo "最终状态检查:"
final_pids=$(find_processes)
if [[ -z "$final_pids" ]]; then
    echo "✓ $APP_NAME 已完全终止"
    exit 0
else
    echo "✗ $APP_NAME 仍有进程在运行: $final_pids"
    echo "请尝试使用强制模式: $0 --force"
    exit 1
fi
EOF
    
    # 替换占位符
    sed -i "s/SCRIPT_VERSION_PLACEHOLDER/${SCRIPT_VERSION}/g" "$script_path"
    sed -i "s/PACKAGE_TIME_PLACEHOLDER/$(date)/g" "$script_path"
    sed -i "s/APP_NAME_PLACEHOLDER/${APP_NAME}/g" "$script_path"
    
    chmod +x "$script_path"
    echo "已创建进程终止脚本: $(basename "$script_path")"
}

# 生成部署说明
create_readme() {
    local target_dir="$1"
    local readme_path="$target_dir/README.txt"
    
    # 获取统计信息
    local lib_count=0
    local symlink_count=0
    local platform_count=0
    local imageformat_count=0
    local resource_count=0
    
    if [[ -d "$target_dir/libs" ]]; then
        lib_count=$(find "$target_dir/libs" -name "*.so*" -type f 2>/dev/null | wc -l)
        symlink_count=$(find "$target_dir/libs" -name "*.so*" -type l 2>/dev/null | wc -l)
    fi
    if [[ -d "$target_dir/plugins/platforms" ]]; then
        platform_count=$(find "$target_dir/plugins/platforms" -name "*.so" -type f 2>/dev/null | wc -l)
    fi
    if [[ -d "$target_dir/plugins/imageformats" ]]; then
        imageformat_count=$(find "$target_dir/plugins/imageformats" -name "*.so" -type f 2>/dev/null | wc -l)
    fi
    if [[ -d "$target_dir/bin" ]]; then
        resource_count=$(( $(find "$target_dir/bin" -type f | wc -l) - 1 ))  # 减去可执行文件本身
    fi
    
    cat > "$readme_path" << EOF
ARM平台应用程序部署说明
==========================================

应用程序: $APP_NAME
打包工具版本: v${SCRIPT_VERSION}
打包时间: $(date)
目标架构: $TARGET_ARCH
资源目录: $RESOURCES_DIR

目录结构:
├── bin/          # 可执行文件和资源文件
├── libs/         # 依赖库文件和符号链接
├── plugins/      # QT插件
└── run_${APP_NAME}.sh  # 运行脚本

部署步骤:
1. 将整个目录复制到ARM设备
2. 给运行脚本添加执行权限: chmod +x run_${APP_NAME}.sh
3. 运行程序: ./run_${APP_NAME}.sh

资源文件说明:
- 配置文件、数据库文件等资源已打包到bin目录
- 程序运行时会在当前目录查找这些文件
- 确保所有必要的资源文件都在bin目录中

平台选择说明:
==========================================
您的QT版本提供了以下平台插件:
- libqlinuxfb.so   : Linux帧缓冲设备，适用于嵌入式系统
- libqminimal.so   : 最小化平台，无图形输出
- libqoffscreen.so : 离屏渲染，无显示输出
- libqvnc.so       : VNC远程桌面

默认使用linuxfb平台，如需更改:
  QT_QPA_PLATFORM=minimal ./run_${APP_NAME}.sh

环境变量设置:
- 设置显示设备: export QT_QPA_PLATFORM=linuxfb:fb=/dev/fb0
- 设置分辨率: export QT_QPA_EGLFS_WIDTH=1920 QT_QPA_EGLFS_HEIGHT=1080

终止脚本说明:
==========================================
目录中包含 kill_${APP_NAME}.sh 脚本，用于终止应用程序进程

使用方法:
- 优雅终止: ./kill_${APP_NAME}.sh
- 强制终止: ./kill_${APP_NAME}.sh --force
- 查看进程: ./kill_${APP_NAME}.sh --info
- 帮助信息: ./kill_${APP_NAME}.sh --help

脚本特性:
1. 首先尝试优雅终止 (SIGTERM)，给程序清理资源的机会
2. 如果优雅终止失败，自动转为强制终止 (SIGKILL)
3. 支持显示当前运行的进程信息
4. 自动过滤掉脚本自身的进程

依赖库信息:
- QT目录: $QT_ARM_DIR
- OpenCV目录: $OPENCV_ARM_DIR
- 工具链: $CROSS_COMPILE_TOOLCHAIN
- 默认资源目录: $DEFAULT_RESOURCES_DIR

常见问题:
1. 如果程序无法启动，请尝试不同的QT平台
2. 嵌入式设备推荐使用linuxfb平台
3. 确保运行脚本有执行权限
4. 检查bin目录中是否包含所有必要的资源文件

打包统计:
- 库文件数量: $lib_count
- 符号链接数量: $symlink_count
- 平台插件: $platform_count
- 图像格式插件: $imageformat_count
- 资源文件: $resource_count
EOF
}

# 验证打包结果
validate_package() {
    local package_dir="$1"
    
    echo "验证打包结果..."
    
    # 检查目录是否存在
    if [[ ! -d "$package_dir" ]]; then
        echo "✗ 错误: 打包目录不存在: $package_dir"
        return 1
    fi
    
    # 检查可执行文件
    if [[ ! -f "$package_dir/bin/$APP_NAME" ]]; then
        echo "✗ 错误: 可执行文件未找到"
        return 1
    fi
    echo "✓ 可执行文件已就位"
    
    # 检查资源文件
    local resource_count=0
    if [[ -d "$package_dir/bin" ]]; then
        resource_count=$(( $(find "$package_dir/bin" -type f | wc -l) - 1 ))  # 减去可执行文件
        if [[ $resource_count -gt 0 ]]; then
            echo "✓ 找到 $resource_count 个资源文件"
            echo "资源文件列表:"
            find "$package_dir/bin" -type f ! -name "$APP_NAME" -exec basename {} \; | while read file; do
                echo "  - $file"
            done
        else
            echo "⚠ 未找到额外的资源文件"
        fi
    fi
    
    # 检查库文件数量
    local lib_count=0
    local symlink_count=0
    if [[ -d "$package_dir/libs" ]]; then
        lib_count=$(find "$package_dir/libs" -name "*.so*" -type f 2>/dev/null | wc -l)
        symlink_count=$(find "$package_dir/libs" -name "*.so*" -type l 2>/dev/null | wc -l)
    fi
    
    if [[ $lib_count -eq 0 ]]; then
        echo "✗ 警告: 未找到任何库文件"
    else
        echo "✓ 找到 $lib_count 个库文件"
    fi
    
    if [[ $symlink_count -gt 0 ]]; then
        echo "✓ 找到 $symlink_count 个符号链接"
    fi
    
    # 检查QT插件
    local platform_plugins=0
    if [[ -d "$package_dir/plugins/platforms" ]]; then
        platform_plugins=$(find "$package_dir/plugins/platforms" -name "*.so" -type f 2>/dev/null | wc -l)
        echo "平台插件列表:"
        ls "$package_dir/plugins/platforms/"*.so 2>/dev/null | xargs -I {} basename {} | while read plugin; do
            echo "  - $plugin"
        done
    fi
    
    if [[ $platform_plugins -gt 0 ]]; then
        echo "✓ 找到 $platform_plugins 个平台插件"
    else
        echo "✗ 警告: 未找到平台插件"
    fi
    
    return 0
}

# 显示最终统计信息
show_final_stats() {
    local package_dir="$1"
    
    echo ""
    echo "最终打包统计:"
    
    if [[ -d "$package_dir" ]]; then
        local dir_size=$(du -sh "$package_dir" 2>/dev/null | cut -f1)
        echo "- 打包目录: $package_dir"
        echo "- 目录大小: ${dir_size:-未知}"
        echo "- 资源目录: $RESOURCES_DIR"
        
        if [[ -d "$package_dir/libs" ]]; then
            local lib_count=$(find "$package_dir/libs" -name "*.so*" -type f 2>/dev/null | wc -l)
            local symlink_count=$(find "$package_dir/libs" -name "*.so*" -type l 2>/dev/null | wc -l)
            echo "- 库文件: $lib_count 个"
            echo "- 符号链接: $symlink_count 个"
        else
            echo "- 库文件: 目录不存在"
        fi
        
        if [[ -d "$package_dir/plugins/platforms" ]]; then
            local platform_count=$(find "$package_dir/plugins/platforms" -name "*.so" -type f 2>/dev/null | wc -l)
            echo "- 平台插件: $platform_count 个"
            echo "- 平台插件列表:"
            ls "$package_dir/plugins/platforms/"*.so 2>/dev/null | xargs -I {} basename {} | while read plugin; do
                echo "  - $plugin"
            done
        else
            echo "- 平台插件: 目录不存在"
        fi
        
        if [[ -d "$package_dir/bin" ]]; then
            local resource_count=$(( $(find "$package_dir/bin" -type f | wc -l) - 1 ))  # 减去可执行文件
            echo "- 资源文件: $resource_count 个"
            if [[ $resource_count -gt 0 ]]; then
                echo "- 资源文件列表:"
                find "$package_dir/bin" -type f ! -name "$APP_NAME" -exec basename {} \; | while read file; do
                    echo "  - $file"
                done
            fi
        else
            echo "- 资源文件: 目录不存在"
        fi

        echo "- 管理脚本:"
        echo "  - 启动脚本: run_${APP_NAME}.sh"
        echo "  - 终止脚本: kill_${APP_NAME}.sh"
    else
        echo "- 打包目录不存在: $package_dir"
    fi
}

# 主函数
main() {
    echo "=========================================="
    echo "QT+OpenCV aarch64应用程序打包工具 v${SCRIPT_VERSION}"
    echo "=========================================="
    echo "应用程序: $APP_NAME"
    echo "输出目录: $OUTPUT_DIR"
    echo "资源目录: $RESOURCES_DIR"
    echo "目标架构: $TARGET_ARCH"
    echo "打包时间: $(date)"
    echo ""
    
    # 检查架构
    check_binary_arch "$EXECUTABLE" || exit 1
    
    # 检查工具链
    check_toolchain
    
    # 检查依赖目录
    if [[ ! -d "$QT_ARM_DIR" ]]; then
        echo "错误: QT目录不存在: $QT_ARM_DIR"
        exit 1
    fi
    if [[ ! -d "$OPENCV_ARM_DIR" ]]; then
        echo "错误: OpenCV目录不存在: $OPENCV_ARM_DIR"
        exit 1
    fi
    
    echo "✓ QT目录: $QT_ARM_DIR"
    echo "✓ OpenCV目录: $OPENCV_ARM_DIR"
    echo "✓ 工具链目录: $CROSS_COMPILE_TOOLCHAIN"
    echo ""
    
    # 创建目录结构
    PACKAGE_DIR="$OUTPUT_DIR/$PACKAGE_NAME"
    echo "创建目录结构: $PACKAGE_DIR"
    mkdir -p "$PACKAGE_DIR/libs" || exit 1
    mkdir -p "$PACKAGE_DIR/plugins/platforms" || exit 1
    mkdir -p "$PACKAGE_DIR/plugins/imageformats" || exit 1
    mkdir -p "$PACKAGE_DIR/plugins/bearer" || exit 1
    mkdir -p "$PACKAGE_DIR/plugins/printsupport" || exit 1
    mkdir -p "$PACKAGE_DIR/bin" || exit 1
    
    # 验证目录创建成功
    if [[ ! -d "$PACKAGE_DIR" ]]; then
        echo "错误: 无法创建打包目录 $PACKAGE_DIR"
        exit 1
    fi
    
    # 复制可执行文件
    echo "复制可执行文件: $APP_NAME"
    cp "$EXECUTABLE" "$PACKAGE_DIR/bin/" || {
        echo "错误: 无法复制可执行文件"
        exit 1
    }
    
    # 复制资源文件
    copy_resources "$RESOURCES_DIR" "$PACKAGE_DIR"
    
    # 复制依赖库
    copy_libraries "$EXECUTABLE" "$PACKAGE_DIR"
    
    # 复制QT核心库（确保基础库存在）
    copy_qt_core_libs "$PACKAGE_DIR"
    
    # 复制OpenCV库
    copy_opencv_libs "$PACKAGE_DIR"
    
    # 复制QT插件
    copy_qt_plugins "$PACKAGE_DIR"
    
    # 创建符号链接
    create_symlinks "$PACKAGE_DIR"
    
    # 生成运行脚本
    create_run_script "$PACKAGE_DIR"

    # 生成杀死进程脚本
    create_kill_script "$PACKAGE_DIR"
    
    # 生成说明文件
    create_readme "$PACKAGE_DIR"
    
    # 验证打包结果
    validate_package "$PACKAGE_DIR"
    
    # 打包成tar.gz
    echo "创建压缩包..."
    cd "$OUTPUT_DIR" || {
        echo "错误: 无法进入输出目录 $OUTPUT_DIR"
        exit 1
    }
    
    tar -czf "${PACKAGE_NAME}.tar.gz" "$PACKAGE_NAME" || {
        echo "错误: 无法创建压缩包"
        exit 1
    }
    
    echo ""
    echo "=========================================="
    echo "打包完成 v${SCRIPT_VERSION}"
    echo "=========================================="
    echo "输出文件: $OUTPUT_DIR/${PACKAGE_NAME}.tar.gz"
    
    local tar_size=$(du -h "${PACKAGE_NAME}.tar.gz" 2>/dev/null | cut -f1)
    echo "压缩包大小: ${tar_size:-未知}"
    echo ""
    echo "部署到ARM设备后，运行: ./run_${APP_NAME}.sh"
    
    # 显示最终统计信息
    show_final_stats "$PACKAGE_DIR"
}

# 运行主函数
main
